package ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.manager.security.impl;

import ace.cmp.core.enums.SystemCodeEnum;
import ace.cmp.core.exception.BusinessException;
import ace.cmp.security.api.exception.ForbiddenI18nException;
import java.util.function.Function;

/**
 * @author caspar
 * @date 2023/9/19 17:16
 */
public abstract class AbstractSecurityManager
    implements ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.manager.security.SecurityManager {

  protected abstract String getSecurityAuthorityPrefix();

  protected abstract String getI18nPrefix();

  protected abstract Function<String, Boolean> getHasAuthorityFn();

  @Override
  public void checkReadAuthority() {
    this.checkAuthority(
        this.getReadAuthoritySuffix(),
        "read-permission-denied",
        SystemCodeEnum.ERROR_HTTP_403_EXCEPTION.getDesc());
  }

  @Override
  public void checkWriteAuthority() {
    this.checkAuthority(
        this.getWriteAuthoritySuffix(),
        "write-permission-denied",
        SystemCodeEnum.ERROR_HTTP_403_EXCEPTION.getDesc());
  }

  @Override
  public void checkRemoveAuthority() {
    this.checkAuthority(
        this.getRemoveAuthoritySuffix(),
        "remove-permission-denied",
        SystemCodeEnum.ERROR_HTTP_403_EXCEPTION.getDesc());
  }

  protected String getWriteAuthoritySuffix() {
    return "write";
  }

  protected String getReadAuthoritySuffix() {
    return "read";
  }

  protected String getRemoveAuthoritySuffix() {
    return "remove";
  }

  /**
   * {@link this#getSecurityAuthorityPrefix()} 安全认证权限前缀,null or empty string 不进行验证.默认为null
   * 验证不通过，抛出异常{@link BusinessException}
   *
   * @param authoritySuffix 权限
   * @param msgCode         提示信息code
   * @param defaultMessage  默认提示信息
   */
  protected void checkAuthority(String authoritySuffix, String msgCode, String defaultMessage) {
    String authorityPrefix = this.getSecurityAuthorityPrefix();

    if (this.hasAuthority(authorityPrefix + "_" + authoritySuffix) == false) {
      throw new ForbiddenI18nException(this.getI18nPrefix() + "." + msgCode, defaultMessage);
    }
  }

  /**
   * 是否包含权限
   *
   * @param authority 权限
   * @return
   */
  protected boolean hasAuthority(String authority) {
    return this.getHasAuthorityFn().apply(authority);
  }
}
